#include "Engine.hpp"
#include "GameWorld.hpp"
#include "RenderSystem.hpp"

using namespace Nano;

class Game : public GameState<Game> {
public:
    GameWorld world;
    RenderSystem* renderer;
    GameObject* camera;
    GameObject* cube;
    float rotation;
    
    void Initialize() {
        
        renderer = world.CreateSystem<RenderSystem>();
        
        camera = world.CreateObject();
        camera->AddComponent<Camera>()->Viewport = Manager().Viewport();
        camera->AddComponent<Transform>()->Position = { 0, 0, 10 };
        camera->GetComponent<Camera>()->FieldOfView = 40;
        
        cube = world.CreateObject();
        cube->AddComponent<Transform>();
        cube->AddComponent<Mesh>()->AddCube(0, 1);
        cube->AddComponent<Material>();
        
        auto& verts = cube->GetComponent<Mesh>()->Vertices();
        
        for (int i=0; i<verts.size(); i++) {
            verts[i].Color = Colour::HslToRgb(0, 1, 1, 1);
        }
        
        rotation = 0;
        
        
        Input.GamePad.AnalogChanged += event_handler(this, &Game::AnalogChanged);
        Input.GamePad.ButtonDown += event_handler(this, &Game::GameButtonDown);
        Input.GamePad.GamePadPluggedIn += event_handler(this, &Game::GamePadPluggedIn);
        Input.GamePad.GamePadUnplugged += event_handler(this, &Game::GamePadUnplugged);
    }
    
    void GamePadPluggedIn(int index) {
         std::cout<<"Gamepad was plugged in " << index << std::endl;
         auto& verts = cube->GetComponent<Mesh>()->Vertices();
        
        for (int i=0; i<verts.size(); i++) {
            verts[i].Color = Colour::HslToRgb(120 + i * 20, 1, 1, 1);
        }
    }
    
    void GamePadUnplugged(int index) {
        std::cout<<"Gamepad was unplugged " << index << std::endl;
        
        auto& verts = cube->GetComponent<Mesh>()->Vertices();
        
        for (int i=0; i<verts.size(); i++) {
            verts[i].Color = Colour::HslToRgb(0 + i * 5, 1, 1, 1);
        }
    }
    
    void GameButtonDown(GamePadData data) {
    
        std::cout << "Button down, GamePad: " << data.GamePad << " button:" << (int)data.Button << std::endl;
 
        if (data.Button == GamePadButton::Back) {
            static int offset = 0;
            offset += 20;
            auto& verts = cube->GetComponent<Mesh>()->Vertices();
            
            for (int i=0; i<verts.size(); i++) {
                verts[i].Color = Colour::HslToRgb(i * 5 + offset, 1, 1, 1);
            }
        } else if (data.Button == GamePadButton::ButtonA) {
            static float size = 1.0f;
            size+=0.1f;
            
            auto& verts = cube->GetComponent<Mesh>()->Vertices();
            
            for (int i=0; i<verts.size(); i++) {
                verts[i].Position = verts[i].Position.Normalized() * size;
            }
        }
    }
    
    void AnalogChanged(GamePadData analog) {
    
        std::cout << "AnalogChanged, GamePad: " << analog.GamePad << " button:" << (int)analog.Button <<"  " << analog.Direction << std::endl;
 
    
        if (analog.Button == GamePadButton::LeftStick) {
            camera->GetComponent<Transform>()->Position += analog.Direction*0.01f;
        } else {
            Quaternion rot = camera->GetComponent<Transform>()->Rotation;
            rot = rot * Quaternion::Create(analog.Direction.x * 0.05f, Vector3(0,1,0));
            camera->GetComponent<Transform>()->Rotation = rot;
        }
    }
    
    void Update(float dt) {
        cube->GetComponent<Transform>()->Rotation = Quaternion(rotation, Vector3(1,0.2f,0.5f).Normalized());
        rotation += dt;
        world.Update(dt);
    }
    
    void Render() {
        renderer->Render();
    }
};

int main() {
    Engine e;
    e.Start<Game>();
	return 0;
}